// i.r(t), i.d(t, { default: () => Navigation })
import Module from "./Module"
import SettingsData from "../data/SettingsData"
import SymbolList from "../SymbolList"
import CameraData from "../data/CameraData"
import transitionTypeEnum from "../enum/transitionType.enum"

import InteractionmodeData from "../data/InteractionmodeData"
import {
  NavigateToSweepCommand,
  NavigateToBox,
  LockNavigationCommand,
  UnlockNavigationCommand,
  FocusOnPinInsideCommand,
  FocusOnPointInsideCommand,
  NavigateToLabelCommand
} from "../command/navigate.command"
import { NavigationException } from "../exception/navigation.exception"

const m = {
  Locked: "Cannot move while navigation is locked",
  InsideOnly: "Cannot navigate between panos when not in Panorama mode",
  InvalidSweep: "Not at a valid sweep",
  InTransition: "Cannot move while in a transition",
  NoDestinationFound: "Cannot move in that direction"
}
import Comparator from "../utils/Comparator"
import SkySphereMesh from "../mesh/SkySphereMesh"
import * as THREE from "three"

import T from "../math/82088"
import { SetCurrentSweepCommand } from "../command/sweep.command"
import { SetMouseCursorCommand } from "../command/cursor.command"

import { MoveToFloorCommand } from "../command/floor.command"
class NavigationInputFocus {
  canStartTransition: any
  commandBinder: any
  input: any
  floorsViewData: any
  navigation: any
  navigationDollhouse: any
  sweepData: any
  cameraModule: any
  toolsData: any
  settingsData: any
  bindings: any[]
  cancelTransition: boolean
  didSetCursor: boolean
  targetFloorId: any
  targetHitPoint: THREE.Vector3
  toggleInput: (e: any) => void
  onRoomClick: (e: any, t: any, i: any) => any
  onBackgroundHover: () => void
  onBackgroundUnhover: () => void
  onFloorChange: () => void
  clearFloorChange: () => void
  changeFloorIfNeeded: () => Promise<void>
  constructor(e, t, i, n, s, r, o, a, l, c) {
    ;(this.canStartTransition = e),
      (this.commandBinder = t),
      (this.input = i),
      (this.floorsViewData = n),
      (this.navigation = s),
      (this.navigationDollhouse = r),
      (this.sweepData = o),
      (this.cameraModule = a),
      (this.toolsData = l),
      (this.settingsData = c),
      (this.bindings = []),
      (this.cancelTransition = !1),
      (this.didSetCursor = !1),
      (this.targetFloorId = null),
      (this.targetHitPoint = new THREE.Vector3()),
      (this.toggleInput = e => {
        this.bindings.forEach(t => (e ? t.renew() : t.cancel()))
      }),
      (this.onRoomClick = (e, t, i) => {
        if (this.shouldIgnore()) return
        if (!this.canStartTransition()) return
        if (!i || !i.point) return
        const n = this.floorsViewData.floors.getFloorByMeshGroup(t.meshGroup)
        if (!n) return
        if (!this.floorsViewData.isNavigable(n.id)) return this.onBackgroundClick()
        if (this.cancelTransition) return
        return 1 !== this.floorsViewData.totalFloors && n.id !== this.floorsViewData.currentFloorId
          ? (this.targetFloorId || ((this.targetFloorId = n.id), this.targetHitPoint.copy(i.point)), !1)
          : this.floorsViewData.roomSelectModeActive || this.floorsViewData.floorSelectModeActive
          ? ((this.cancelTransition = !0),
            this.cameraModule
              .cancelTransition()
              .then(() => this.navigation.navigateToPanoNearIntersection(i))
              .then(() => {
                this.cancelTransition = !1
              }),
            void this.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.DEFAULT)))
          : void (this.floorsViewData.floorSelectModeActive
              ? (this.cancelTransition = !1)
              : this.navigationDollhouse.navigateToPoint(i.point).then(() => {
                  this.cancelTransition || this.setFocusSweep(i), (this.cancelTransition = !1)
                }))
      }),
      (this.onBackgroundClick = () => {
        if (!this.shouldIgnore() && this.canStartTransition() && !this.cancelTransition) {
          if (this.targetFloorId) return !1
          ;(this.cancelTransition = !0),
            this.cameraModule
              .cancelTransition()
              .then(() => this.commandBinder.issueCommand(new MoveToFloorCommand(null, !1)))
              .then(() => {
                this.cancelTransition = !1
              })
        }
      }),
      (this.onBackgroundHover = () => {
        if (this.shouldIgnore()) return
        const { activeToolName: e } = this.toolsData
        null !== this.floorsViewData.currentFloorId &&
          e !== ToolsList.LABELS &&
          ((this.didSetCursor = !0), this.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.FINGER)))
      }),
      (this.onBackgroundUnhover = () => {
        this.shouldIgnore() || (this.didSetCursor && (this.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.DEFAULT)), (this.didSetCursor = !1)))
      }),
      (this.onFloorChange = () => {
        this.shouldIgnore() || (null === this.floorsViewData.currentFloorId && this.commandBinder.issueCommand(new SetMouseCursorCommand(cursorEnum.DEFAULT)))
      }),
      (this.clearFloorChange = () => {
        this.targetFloorId = null
      }),
      (this.changeFloorIfNeeded = async () => {
        this.targetFloorId &&
          (await this.commandBinder.issueCommand(new MoveToFloorCommand(this.targetFloorId, !1, void 0, this.targetHitPoint)), (this.targetFloorId = null))
      }),
      this.bindings.push(
        this.input.registerMeshHandler(ClickEvent, Comparator.is(funcUtil.raycastVisible), this.onRoomClick),
        this.input.registerUnfilteredHandler(ClickEvent, this.clearFloorChange),
        this.input.registerHandler(ClickEvent, this.changeFloorIfNeeded),
        this.input.registerMeshHandler(ClickEvent, Comparator.isType(SkySphereMesh), this.onBackgroundClick),
        this.input.registerMeshHandler(HoverEvent, Comparator.isType(SkySphereMesh), this.onBackgroundHover),
        this.input.registerMeshHandler(UnhoverEvent, Comparator.isType(SkySphereMesh), this.onBackgroundUnhover),
        this.floorsViewData.makeFloorChangeSubscription(this.onFloorChange)
      )
  }
  onBackgroundClick: any
  async setFocusSweep(e) {
    if (!this.canStartTransition()) return
    if (this.cancelTransition) return
    const t = T.bG(this.sweepData, !1, e)
    t.length > 0 && t[0].sweep && (await this.commandBinder.issueCommand(new SetCurrentSweepCommand(t[0].sweep.id)))
  }
  shouldIgnore() {
    return !this.settingsData.tryGetProperty(keyConst.rule.features.roomnav, !1)
  }
}
import Vectors from "../three/Vectors"
import { ScrollEvent } from "../event/ScrollEvent"
import { KeyEvent } from "../event/KeyEvent"
import ModelColliderTarget from "../mesh/ModelColliderTarget"
import L from "../packages/76870"
import Logger from "../utils/Logger"

const k = new Logger("nav-input")
class NavigationInputInside {
  navigation: any
  inputIni: any
  insideNav: any[]
  insideVrNav: any[]
  toggleInput: (e: any) => void
  toggleVrInput: (e: any) => void
  registerInsideClickHandlers: (e: any) => any[]
  registerVrClickHandlers: (e: any) => any[]
  registerWheelInput: (e: any) => any[]
  hotkeys: (e: any) => any[]
  static hotkeyDirections: any
  continuousMovementHotkey: any
  constructor(e, t, i) {
    ;(this.navigation = e),
      (this.inputIni = t),
      (this.insideNav = []),
      (this.insideVrNav = []),
      (this.toggleInput = e => {
        this.insideNav.forEach(t => (e ? t.renew() : t.cancel()))
      }),
      (this.toggleVrInput = e => {
        this.insideVrNav.forEach(t => (e ? t.renew() : t.cancel()))
      }),
      (this.registerInsideClickHandlers = e => [
        e.registerMeshHandler(ClickEvent, Comparator.is(funcUtil.raycastVisible), (e, t, i) =>
          this.tryExecuteAction(
            (e, t) => V(e) && B(t),
            (e, t) => B(t) && this.navigation.navigateTowardsIntersection(t),
            e,
            i
          )
        ),
        e.registerMeshHandler(ClickEvent, Comparator.isType(SkySphereMesh), (e, t, i) =>
          this.tryExecuteAction(
            (e, t) => V(e) && B(t),
            (e, t) => B(t) && this.navigation.navigateTowardsIntersection(t),
            e,
            i
          )
        )
      ]),
      (this.registerVrClickHandlers = e => [
        e.registerMeshHandler(ClickEvent, Comparator.isInstanceOf(ModelColliderTarget), (e, t, i) =>
          this.tryExecuteAction(
            (e, t) => V(e) && B(t),
            (e, t) => B(t) && this.navigation.navigateToPanoNearIntersection(t),
            e,
            i
          )
        )
      ]),
      (this.registerWheelInput = e => [
        e.registerHandler(ScrollEvent, e =>
          this.tryExecuteAction(
            e => !0,
            e => {
              if (e instanceof ScrollEvent) {
                const t = new THREE.Vector3(0, 0, Math.sign(e.delta.y))
                return !!this.navigation.navigateInLocalDirection(t)
              }
              return !1
            },
            e
          )
        )
      ]),
      (this.hotkeys = e => [
        e.registerHandler(KeyEvent, e =>
          this.tryExecuteAction(
            e => (U(e) || F(e)) && e.key in NavigationInputInside.hotkeyDirections,
            e => {
              if (U(e)) {
                this.continuousMovementHotkey = e.key
                const t = NavigationInputInside.hotkeyDirections[e.key]
                this.navigation.setContinuousNavigationLocalDirection(t)
              } else F(e) && e.key === this.continuousMovementHotkey && this.navigation.setContinuousNavigationLocalDirection()
              return !1
            },
            e
          )
        )
      ]),
      (this.tryExecuteAction = (e, t, i, n) => {
        let s = !1
        try {
          this.navigation.isNavigationInputAllowed() && e(i, n) && (s = t(i, n))
        } catch (e) {
          if (!(e instanceof NavigationException)) throw (k.warn(e), e)
          k.debug(e)
        }
        return s
      }),
      this.insideVrNav.push(...this.registerVrClickHandlers(this.inputIni)),
      this.insideNav.push(...this.registerInsideClickHandlers(this.inputIni), ...this.hotkeys(this.inputIni)),
      i && this.insideNav.push(...this.registerWheelInput(this.inputIni))
  }
  tryExecuteAction(e, t, i, n?) {
    let s = !1
    try {
      this.navigation.isNavigationInputAllowed() && e(i, n) && (s = t(i, n))
    } catch (e) {
      if (!(e instanceof NavigationException)) throw (k.warn(e), e)
      k.debug(e)
    }
    return s
  }
  get bindings() {
    return [...this.insideNav, ...this.insideVrNav]
  }
}
function B(e) {
  return void 0 !== e && void 0 !== e.point
}
function U(e) {
  return e instanceof KeyEvent && e.state === KeyState.DOWN
}
function F(e) {
  return e instanceof KeyEvent && e.state === KeyState.UP
}
function V(e) {
  return e instanceof ClickEvent && e.button === L.MP.PRIMARY
}
NavigationInputInside.hotkeyDirections = {
  [hotKeyEnum.W]: Vectors.FORWARD,
  [hotKeyEnum.A]: Vectors.LEFT,
  [hotKeyEnum.S]: Vectors.BACK,
  [hotKeyEnum.D]: Vectors.RIGHT,
  [hotKeyEnum.UPARROW]: Vectors.FORWARD,
  [hotKeyEnum.DOWNARROW]: Vectors.BACK
}
const H = new Logger("nav-input")
class NavigationInputOutside {
  navigation: any
  input: any
  settings: any
  bindings: any[]
  toggleInput: (e: any) => void
  constructor(e, t, i) {
    ;(this.navigation = e),
      (this.input = t),
      (this.settings = i),
      (this.bindings = []),
      (this.toggleInput = e => {
        H.debug("toggling dollhouse input", e), this.bindings.forEach(t => (e ? t.renew() : t.cancel()))
      }),
      this.bindings.push(...this.registerEnterPanoHandler())
  }
  registerEnterPanoHandler() {
    return [
      this.input.registerMeshHandler(
        ClickEvent,
        Comparator.isInstanceOf(ModelColliderTarget),
        (e, t, i) =>
          !this.settings.tryGetProperty(keyConst.rule.features.roomnav, !1) &&
          !!this.navigation.isNavigationInputAllowed() &&
          e.button === L.MP.PRIMARY &&
          void 0 !== i &&
          this.navigation.navigateToPanoNearIntersection(i)
      )
    ]
  }
}
import SweepData from "../data/SweepData"
import ViewmodeData from "../data/ViewmodeData"
import playerConst from "../constant/player.const"
import CameraModule from "./CameraModule"
import FloorsViewData from "../data/FloorsViewData"
import RaycasterModule from "./RaycasterModule"
import SweepDataModule from "./SweepDataModule"
import ToolsData from "../data/ToolsData"
import ViewmodeModule from "./ViewmodeModule"
import J from "../math/7170"
import ee from "../math/69626"
import OpenDeferred from "../utils/OpenDeferred"

class NavigationDollhouse {
  canStartTransition: any
  pose: any
  cameraModule: any
  navigateToPoint: (e: any) => Promise<void>
  navigateToBox: (e: any) => any
  constructor(e, t, i) {
    ;(this.canStartTransition = e),
      (this.pose = t),
      (this.cameraModule = i),
      (this.navigateToPoint = async e => {
        if (!this.canStartTransition()) return
        const t = this.pose.focalDistance,
          i = ee.fd(this.pose.rotation, e, t)
        await this.cameraModule.cancelTransition(),
          await this.cameraModule.moveTo({
            pose: { position: i },
            transitionType: transitionTypeEnum.Interpolate,
            focalDistance: t,
            transitionTime: configConst.NavigationConfig.TRANSITION_TIME_DH
          })
      }),
      (this.navigateToBox = e => {
        if (!this.canStartTransition()) return OpenDeferred.resolve()
        const { position: t, rotation: i, focalDistance: n } = this.getPoseForBox(e)
        return this.cameraModule.moveTo({
          pose: { position: t, rotation: i },
          transitionType: transitionTypeEnum.Interpolate,
          focalDistance: n,
          transitionTime: configConst.NavigationConfig.TRANSITION_TIME_DH
        })
      }),
      (this.getPoseForBox = e => {
        const t = e.getCenter(new THREE.Vector3()),
          i = e.getSize(new THREE.Vector3()),
          n = i.z > i.x
        let s = this.pose.rotation
        s = n
          ? s.angleTo(ne.LANDSCAPE_LEFT) > s.angleTo(ne.LANDSCAPE_RIGHT)
            ? ne.LANDSCAPE_LEFT
            : ne.LANDSCAPE_RIGHT
          : s.angleTo(ne.PORTRAIT_RIGHT) > s.angleTo(ne.PORTRAIT_LEFT)
          ? ne.PORTRAIT_LEFT
          : ne.PORTRAIT_RIGHT
        const r = -85 * J.Ue,
          o = 2 * Math.atan(1 / this.pose.projection.elements[5]),
          a = ee.YN(t, s, r, e, 1.2 * o, this.pose.aspect()),
          l = t.distanceTo(a.position)
        return {
          position: a.position,
          rotation: a.rotation,
          focalDistance: l
        }
      })
  }
  getPoseForBox: any
}
const ne = {
  LANDSCAPE_LEFT: new THREE.Quaternion().setFromAxisAngle(Vectors.UP, 45 * J.Ue),
  LANDSCAPE_RIGHT: new THREE.Quaternion().setFromAxisAngle(Vectors.UP, -45 * J.Ue),
  PORTRAIT_LEFT: new THREE.Quaternion().setFromAxisAngle(Vectors.UP, 25 * J.Ue),
  PORTRAIT_RIGHT: new THREE.Quaternion().setFromAxisAngle(Vectors.UP, -25 * J.Ue)
}
import se from "../math/51263"
import re from "../math/57051"
import oe from "../math/19674"
import ae from "../math/27687"
import le from "../math/45870"
const ce = !0,
  he = 8,
  de = 0.1,
  ue = 25,
  pe = 500
class NavigationPoint {
  engine: any
  cameraData: any
  sweepData: any
  viewmodeModule: any
  raycaster: any
  tryNavigateToPoint: (e: any, t: any, i: any, n: any) => Promise<boolean>
  commandBinder: any
  constructor(e, t, i, n, s) {
    ;(this.engine = e),
      (this.cameraData = t),
      (this.sweepData = i),
      (this.viewmodeModule = n),
      (this.raycaster = s),
      (this.tryNavigateToPoint = async (e, t, i, n) => {
        const s = [],
          r = []
        if (
          (s.push(se._T()),
          s.push(se._k()),
          t === transitionTypeEnum.Interpolate && isPanOrMesh(this.viewmodeModule.currentMode) && this.sweepData.currentSweep)
        ) {
          const t = 0.5,
            i = this.sweepData.currentSweep,
            n = this.sweepData.getSweep(i),
            o = n.position.clone().sub(e).normalize()
          s.push(se.pI(e, o, t)), s.push(se.T3(n)), r.push(re.o7(e, o))
        }
        s.push(this.withinLatitudeFilter(e)), s.push(this.notTooCloseFilter(e)), s.push(this.notTooFarFilter(e))
        r.push(re.Dv(e, -2))
        const o = this.sweepData.sortByScore(s, r),
          a = new THREE.Vector3()
        let l = null,
          h = !1,
          d = null
        for (const s of o)
          if (this.sweepCanSeeNote(e, s.sweep)) {
            if (((d = s.sweep), t === transitionTypeEnum.Interpolate)) {
              a.copy(e).sub(d.position).normalize(), (h = !0)
              const s = this.getSweepToPointRotation(d.position, e, n),
                r = this.cameraData.pose.projection.asThreeMatrix4(),
                { width: o, height: p } = this.cameraData,
                m = ae.bD(e, d.position, s, o, p, r)
              i && i(m),
                (l = isPanOrMesh(this.viewmodeModule.currentMode)
                  ? this.commandBinder.issueCommand(
                      new NavigateToSweepCommand({
                        transition: t || transitionTypeEnum.Interpolate,
                        sweep: d.id,
                        rotation: s
                      })
                    )
                  : this.viewmodeModule.switchToMode(viewmodeEnum.Panorama, t, {
                      rotation: s,
                      sweepID: d.id
                    }))
            }
            break
          }
        return (
          !(!d || (!h && t === transitionTypeEnum.Interpolate)) &&
          (l ||
            (l = this.engine.commandBinder.issueCommand(
              new NavigateToSweepCommand({
                transition: t,
                transitionTime: pe,
                sweep: d.id,
                rotation: this.getSweepToPointRotation(d.position, e, n)
              })
            )),
          l && (await l),
          !0)
        )
      }),
      (this.getSweepToPointRotation = (e, t, i) => {
        const n = ee.n0(e, t)
        return i && n.multiply(i), oe.Z(n)
      }),
      (this.notTooCloseFilter = e => t => Math.abs(t.position.x - e.x) > de || Math.abs(t.position.z - e.z) > de),
      (this.notTooFarFilter = e => t => {
        if (!ce) {
          return t.position.distanceTo(e) > he
        }
        return !0
      }),
      (this.withinLatitudeFilter = e => t => {
        const i = new THREE.Vector3().copy(e).sub(t.position),
          n = -Math.atan(i.y / Math.sqrt(i.x * i.x + i.z * i.z)),
          s = J.Id(ue)
        return le.zf - s < n && n < le.uQ + s
      }),
      (this.commandBinder = e.commandBinder)
  }
  withinLatitudeFilter: any
  notTooCloseFilter: any
  notTooFarFilter: any
  getSweepToPointRotation: any
  async focusPin(e, t, i, n) {
    const { anchorPosition: s, stemNormal: r, stemLength: o } = e,
      a = s.clone().add(r.clone().setLength(o))
    return this.focusPoint(a, t, i, n)
  }
  async focusPoint(e, t, i, n) {
    if (this.cameraData.canTransition() && this.sweepData.canTransition() && !(await this.tryNavigateToPoint(e, t, i, n))) {
      if (t !== transitionTypeEnum.Interpolate) return this.goToNearestSweep(e, t, i, n)
      try {
        await this.commandBinder.issueCommand(new ChangeViewmodeCommand(modeEnum.DOLLHOUSE, transitionTypeEnum.Interpolate))
      } catch (s) {
        await this.goToNearestSweep(e, t, i, n)
      }
      ;(await this.tryNavigateToPoint(e, t, i, n)) || (await this.goToNearestSweep(e, t, i, n))
    }
  }
  async goToNearestSweep(e, t, i, n) {
    const s = e,
      r = this.sweepData.getClosestSweep(s, !0)
    if (!r) throw new Error("Cannot find sweep closest to Mattertag disc")
    const o = this.getSweepToPointRotation(r.position, s, n),
      a = this.cameraData.pose.projection.asThreeMatrix4(),
      { width: l, height: h } = this.cameraData,
      d = ae.bD(s, r.position, o, l, h, a)
    i && i(d),
      await this.commandBinder.issueCommand(
        new NavigateToSweepCommand({
          sweep: r.id,
          rotation: o,
          transition: t || transitionTypeEnum.Interpolate
        })
      )
  }
  sweepCanSeeNote(e, t) {
    const i = new THREE.Vector3().copy(e).sub(t.position),
      n = i.length()
    i.normalize()
    let s = this.raycaster.picking.pick(t.position, i, funcUtil.raycastVisible)
    return (!s || s.distance > n) && (s = this.raycaster.picking.pick(e, i.negate(), funcUtil.raycastVisible)), !s || n <= s.distance
  }
}

import keyConst from "../constant/key.const"
import configConst from "../constant/config.const"

const fe = new Logger("walk")
class NavigationWalking {
  cameraPose: any
  sweepTransition: any
  sweepControl: any
  cameraControl: any
  generators: any
  navigation: any
  active: boolean
  path: any[]
  lastQueueTime: number
  repeatedQueueDelayMS: number
  positionTracker: DynamicNumber
  baseTransitionTime: any
  baseTransitionSpeed: any
  nextSweep: any
  continuousMovementDirection: any
  startingSweep: any
  generator: any
  activePromise: Promise<void>
  constructor(e, t, i, n, s, r, o) {
    ;(this.cameraPose = e),
      (this.sweepTransition = t),
      (this.sweepControl = i),
      (this.cameraControl = n),
      (this.generators = s),
      (this.navigation = r),
      (this.active = !1),
      (this.path = []),
      (this.lastQueueTime = 0),
      (this.repeatedQueueDelayMS = 150),
      (this.positionTracker = new DynamicNumber().setAccel(15).setMaxSpeed(5)),
      (this.baseTransitionTime = configConst.transitionConfig.camera.baseTransitionTime),
      (this.baseTransitionSpeed = configConst.transitionConfig.camera.transitionSpeed),
      o.onPropertyChanged(keyConst.baseTransitionSpeedKey, e => {
        this.baseTransitionTime = e
      })
  }
  get isActive() {
    return this.active
  }
  get targetSweep() {
    return this.nextSweep
  }
  setContinuousMovementDirection(e) {
    ;(this.continuousMovementDirection = e), !this.active && e && this.navigation.navigateInLocalDirection(e)
  }
  stop() {
    ;(this.path.length = 0),
      this.cameraControl.endExternalTransition(),
      (this.startingSweep = void 0),
      (this.nextSweep = void 0),
      (this.active = !1),
      this.generator && (this.generators.stopGenerator(this.generator), (this.generator = null))
  }
  appendNode(e, t) {
    if (!this.canQueueSweeps(e)) return Promise.resolve()
    if (!e) return Promise.resolve()
    if ((this.path.push(e), (this.lastQueueTime = Date.now()), !this.active)) {
      this.startingSweep = t
      const { generator: i, deferred: n } = this.createTransition()
      this.generators.startGenerator(i),
        (this.generator = i),
        (this.activePromise = n.nativePromise().then(() => {
          this.activePromise = null
        })),
        this.positionTracker.setEndValue(this.getDistanceToSweep(e)),
        this.positionTracker.commit(),
        this.checkForSpeedIncrease(e)
    }
    return this.activePromise ? this.activePromise : Promise.resolve()
  }
  canQueueSweeps(e?) {
    if (e && this.path.indexOf(e) >= 0) return !1
    return !(this.path.length >= 2) && !(this.active && Date.now() - this.lastQueueTime < this.repeatedQueueDelayMS)
  }
  attemptContinuousNavigation() {
    try {
      this.continuousMovementDirection && this.navigation.navigateInLocalDirection(this.continuousMovementDirection)
    } catch (e) {
      if (!(e instanceof NavigationException)) throw (fe.warn(e), e)
      fe.debug(e)
    }
  }
  createTransition() {
    const e = this,
      t = new OpenDeferred()
    return {
      generator: function* () {
        e.active = !0
        let i = Date.now()
        e.cameraControl.beginExternalTransition()
        const n = new THREE.Vector3().copy(e.cameraPose.position),
          s = new THREE.Vector3(),
          r = new THREE.Vector3(),
          o = e.positionTracker
        for (o.setMaxSpeed(5).setAccel(15); e.path.length > 0; ) {
          const t = e.nextSweep ? e.nextSweep.id : e.startingSweep,
            a = e.path.shift()
          if (!a) {
            e.nextSweep = void 0
            break
          }
          ;(e.nextSweep = a), n.copy(e.cameraPose.position)
          const l = n.distanceTo(a.position)
          for (
            o.setStartValue(0).setEndValue(l).setInitialSpeed(o.speed).activate(!0).commit(),
              r.subVectors(a.position, n),
              r.normalize(),
              yield new WaitForPromiseGeneratorResult(e.sweepControl.activateSweepUnsafe({ sweepId: a.id })),
              e.sweepControl.beginSweepTransition({
                sweepId: a.id,
                internalProgress: !1,
                prevSweepId: t
              }),
              o.start(),
              e.checkForSpeedIncrease(a);
            o.active;

          ) {
            const t = Date.now() - i,
              l = 0 === e.path.length
            let c = !1,
              h = !1
            if (!l) {
              const t = e.path[0]
              c = o.endValue - o.currentValue + a.position.distanceTo(t.position) < o.getSlowdownDistance()
              const i = s.subVectors(t.position, a.position)
              i.normalize()
              r.dot(i) < 0.3 && (h = !0)
            }
            o.setSlowdown(l || c || h), o.tick(t)
            const d = o.getProgressPercent()
            e.cameraControl.updateCameraPosition(s.lerpVectors(n, a.position, d)),
              e.sweepTransition.progress.modifyAnimation(d, 1, 0),
              (i = Date.now()),
              e.continuousMovementDirection && e.canQueueSweeps() && o.isSlowingDown && e.attemptContinuousNavigation(),
              o.active && (yield new NullGeneratorResult())
          }
          e.sweepControl.endSweepTransition({
            sweepId: a.id,
            prevSweepId: t
          })
        }
        t.resolve(), e.stop()
      },
      deferred: t
    }
  }
  getDistanceToSweep(e) {
    return (this.nextSweep ? this.nextSweep.position : this.cameraPose.position).distanceTo(e.position)
  }
  checkForSpeedIncrease(e) {
    const t = this.positionTracker,
      i = this.getDistanceToSweep(e),
      n = t.endValue - t.currentValue,
      s = n + i - t.getSlowdownDistance()
    if (n + i > 12) {
      const e = this.baseTransitionTime,
        i = this.baseTransitionSpeed,
        n = 0.001 * (e + Math.log2(1 + s) * configConst.TRANSITION_DISTANCE_MULTIPLIER * i) - t.maxSpeed / t.acceleration,
        r = s / n
      n > 0 && t.setMaxSpeed(r).setDesiredAcceleration(3 * r)
    } else t.setMaxSpeed(5).setDesiredAcceleration(15)
    t.commit()
  }
}
import ve from "../math/79437"
import { ChangeViewmodeCommand } from "../command/viewmode.command"
import funcUtil from "../utils/func.util"
import optionsKeyEnum from "../enum/optionsKey.enum"
import cursorEnum from "../enum/cursor.enum"
import DynamicNumber from "../object/DynamicNumber"
import { ToolsList } from "../enum/tool.enum"
import modeEnum from "../enum/mode.enum"
import { ClickEvent, HoverEvent, UnhoverEvent } from "../event/GestureEvent"
import { NullGeneratorResult, WaitForPromiseGeneratorResult } from "../engine/EngineGenerators"
import hotKeyEnum, { KeyState } from "../enum/hotKey.enum"
import { isPanOrMesh } from "../utils/viewmode.util"
import viewmodeEnum from "../enum/viewmode.enum"
class NavigationLabel {
  engine: any
  settingsData: any
  cameraData: any
  cameraModule: any
  viewmodeData: any
  floorsViewData: any
  toolsData: any
  constructor(e, t, i, n, s, r, o) {
    ;(this.engine = e),
      (this.settingsData = t),
      (this.cameraData = i),
      (this.cameraModule = n),
      (this.viewmodeData = s),
      (this.floorsViewData = r),
      (this.toolsData = o)
  }
  async enforceLabelEditorFriendlyViewmode(e) {
    var t
    let i = this.settingsData.tryGetProperty(keyConst.rule.features.roomnav, !1) && this.viewmodeData.isDollhouse()
    this.toolsData.activeToolName !== ToolsList.LABELS && (i &= this.settingsData.tryGetProperty(optionsKeyEnum.LabelsDollhouse, !0))
    let n = !0
    if ((await (null === (t = this.cameraData.transition.promise) || void 0 === t ? void 0 : t.nativePromise()), !this.viewmodeData.isFloorplan() && !i))
      try {
        await this.engine.commandBinder.issueCommand(new ChangeViewmodeCommand(modeEnum.FLOORPLAN, transitionTypeEnum.Interpolate))
      } catch (e) {
        n = !1
      }
    return (
      ((e && e !== this.floorsViewData.currentFloorId) || null === this.floorsViewData.currentFloorId) &&
        (await this.engine.commandBinder.issueCommand(new MoveToFloorCommand(e || this.floorsViewData.getHighestVisibleFloorId()))),
      n
    )
  }
  async navigateToLabel(e) {
    const t = await this.enforceLabelEditorFriendlyViewmode(e.floorId)
    return (
      this.viewmodeData.isFloorplan()
        ? await this.panToLabelFloorplan(e.position)
        : this.viewmodeData.isDollhouse() && (await this.panToLabelDollhouse(e.position)),
      t
    )
  }
  async panToLabelDollhouse(e) {
    this.cameraModule.canTransition() || (await this.cameraModule.cancelTransition())
    const t = new THREE.Box3()
    t.setFromCenterAndSize(new THREE.Vector3(0, 1, 0).add(e), new THREE.Vector3(4, 4, 4)),
      await this.engine.commandBinder.issueCommand(new NavigateToBox({ box: t }))
  }
  async panToLabelFloorplan(e) {
    this.cameraModule.canTransition() || (await this.cameraModule.cancelTransition())
    const t = new THREE.Plane(),
      i = new THREE.Vector3(0, 0, 1).applyQuaternion(this.cameraData.pose.rotation),
      n = e
    t.setFromNormalAndCoplanarPoint(i, n)
    const s = ee.Fe(this.cameraData.pose.position, this.cameraData.pose.rotation, t)
    if (!s) return
    const r = new THREE.Vector3().copy(n).sub(s),
      o = new THREE.Vector3().copy(this.cameraData.pose.position).add(r)
    await this.cameraModule.moveTo({
      transitionType: transitionTypeEnum.Interpolate,
      pose: { position: o },
      transitionTime: 1e3,
      easing: ve.hl
    })
  }
}
const be = new Logger("navigation")
export default class Navigation extends Module {
  navigationEnabled: boolean
  inputOutside: any[]
  navigationRules: (() => boolean)[]
  addNavigationRule: (e: any) => void
  removeNavigationRule: (e: any) => void
  isNavigationInputAllowed: () => boolean
  commandBinder: any
  navigationPoint: any
  navigationLabel: any
  settingsData: any
  sweepData: any
  sweepModule: any
  viewmodeData: any
  viewmodeModule: any
  cameraData: any
  cameraModule: any
  interactionmodeData: any
  navigationDollhouse: NavigationDollhouse
  inputInside: NavigationInputInside
  navigationWalk: NavigationWalking
  constructor() {
    super(...arguments),
      (this.name = "navigation"),
      (this.navigationEnabled = !0),
      (this.inputOutside = []),
      (this.navigationRules = [() => !0]),
      (this.addNavigationRule = e => {
        ;-1 === this.navigationRules.indexOf(e) && this.navigationRules.push(e)
      }),
      (this.removeNavigationRule = e => {
        const t = this.navigationRules.indexOf(e)
        ;-1 !== t && this.navigationRules.splice(t, 1)
      }),
      (this.isNavigationInputAllowed = () => {
        const e = this.navigationRules.reduce((e, t) => e && t(), !0)
        return (
          !(!this.navigationEnabled || !e) ||
          (be.debug("Cannot move while navigation is locked", {
            blockedByRules: !e,
            blockedByCommand: !this.navigationEnabled
          }),
          !1)
        )
      })
  }
  async init(e, t) {
    ;(this.commandBinder = t.commandBinder),
      this.bindings.push(
        this.commandBinder.addBinding(LockNavigationCommand, async () => this.lockNavigation()),
        this.commandBinder.addBinding(UnlockNavigationCommand, async () => this.unlockNavigation()),
        this.commandBinder.addBinding(NavigateToBox, async e => this.navigateToBox(e.box)),
        this.commandBinder.addBinding(FocusOnPointInsideCommand, async e => {
          const { focusPosition: t, transition: i, orientationAdjust: n, onSweepChosen: s } = e
          return this.navigationPoint.focusPoint(t, i, s, n)
        }),
        this.commandBinder.addBinding(FocusOnPinInsideCommand, async e => {
          const { pinPosition: t, transition: i, orientationAdjust: n, onSweepChosen: s } = e
          return this.navigationPoint.focusPin(t, i, s, n)
        }),
        this.commandBinder.addBinding(NavigateToSweepCommand, e =>
          this.navigateToSweep(e.sweep, e.rotation, e.transition, e.transitionTime, e.transitionSpeedMultiplier)
        ),
        this.commandBinder.addBinding(NavigateToLabelCommand, async ({ position: e, floorId: t, viewmodeOnly: i }) =>
          i
            ? this.navigationLabel.enforceLabelEditorFriendlyViewmode()
            : !(!e || !t) &&
              this.navigationLabel.navigateToLabel({
                position: e,
                floorId: t
              })
        )
      ),
      ([
        this.settingsData,
        this.sweepData,
        this.sweepModule,
        this.viewmodeData,
        this.viewmodeModule,
        this.cameraData,
        this.cameraModule,
        this.interactionmodeData
      ] = await Promise.all([
        t.market.waitForData(SettingsData),
        t.market.waitForData(SweepData),
        t.getModule(SweepDataModule),
        t.market.waitForData(ViewmodeData),
        t.getModule(ViewmodeModule),
        t.market.waitForData(CameraData),
        t.getModule(CameraModule),
        t.market.waitForData(InteractionmodeData)
      ]))
    const [i, n, c] = await Promise.all([t.getModule(RaycasterModule), t.market.waitForData(ToolsData), t.market.waitForData(FloorsViewData)])
    ;(this.navigationPoint = new NavigationPoint(t, this.cameraData, this.sweepData, this.viewmodeModule, i)),
      (this.navigationLabel = new NavigationLabel(t, this.settingsData, this.cameraData, this.cameraModule, this.viewmodeData, c, n))
    const h = await t.getModuleBySymbol(SymbolList.INPUT)
    this.inputOutside.push(new NavigationInputOutside(this, h, this.settingsData))
    const p = () => this.isNavigationInputAllowed() && this.viewmodeData.canStartTransition() && !c.transitionActive && this.sweepData.canTransition(),
      m = () => p() && (this.viewmodeData.isDollhouse() || this.viewmodeData.isFloorplan() || this.viewmodeData.isOrthographic())
    ;(this.navigationDollhouse = new NavigationDollhouse(m, this.cameraData.pose, this.cameraModule)),
      this.inputOutside.push(
        new NavigationInputFocus(m, t.commandBinder, h, c, this, this.navigationDollhouse, this.sweepData, this.cameraModule, n, this.settingsData)
      ),
      (this.inputInside = new NavigationInputInside(this, h, !!e.enableWheel)),
      this.inputOutside.forEach(e => this.bindings.push(...e.bindings)),
      this.bindings.push(...this.inputInside.bindings),
      this.updateInputBindings(),
      this.bindings.push(
        this.viewmodeData.makeModeChangeSubscription(() => {
          this.viewmodeData.currentMode !== viewmodeEnum.Transition && this.updateInputBindings()
        })
      ),
      (this.navigationWalk = new NavigationWalking(
        this.cameraData.pose,
        this.sweepData.transition,
        this.sweepModule,
        this.cameraModule,
        t,
        this,
        this.settingsData
      ))
  }
  updateInputBindings() {
    const e = this.interactionmodeData.isVR(),
      t = this.viewmodeData.isInside()
    this.inputInside.toggleInput(t && !e), this.inputInside.toggleVrInput(t && e), this.inputOutside.forEach(e => e.toggleInput(!t))
  }
  navigateInLocalDirection(e) {
    const t = this.cameraData.pose.rotation
    return this.navigateInDirection(e.clone().applyQuaternion(t))
  }
  setContinuousNavigationLocalDirection(e) {
    this.navigationWalk.setContinuousMovementDirection(e)
  }
  navigateTowardsIntersection(e) {
    return !!this.navigateInDirection(e.point.clone().sub(this.cameraData.pose.position))
  }
  navigateToPanoNearIntersection(e) {
    const t = T.bG(this.sweepData, this.viewmodeData.isInside(), e),
      i = t.length > 0 ? t[0].sweep : this.sweepData.getClosestSweep(e.point, !0),
      n = configConst.tourAniType[this.interactionmodeData.mode]
    if (this.viewmodeData.isInside() && i) return this.navigateToSweep(i.id, void 0, n), !0
    if (this.viewmodeData.canSwitchViewMode(viewmodeEnum.Panorama)) {
      const e = i ? i.id : void 0
      return this.commandBinder.issueCommand(new ChangeViewmodeCommand(modeEnum.INSIDE, n, { sweepID: e })), !0
    }
    return !1
  }
  navigateInDirection(e) {
    if (!this.viewmodeData.isInside()) throw new NavigationException(m.InsideOnly)
    if (!this.sweepData.currentSweep) throw new NavigationException(m.InvalidSweep)
    const t = configConst.tourAniType[this.interactionmodeData.mode],
      i = T.Tq(this.sweepData, e, this.navigationWalk.isActive ? 0.65 : void 0, this.navigationWalk.isActive ? this.navigationWalk.targetSweep : void 0)
    if (i.length > 0 && i[0].sweep) return this.navigateToSweep(i[0].sweep.id, void 0, t)
    throw new NavigationException(m.NoDestinationFound)
  }
  async navigateToBox(e) {
    return this.navigationDollhouse.navigateToBox(e)
  }
  lockNavigation() {
    ;(this.navigationEnabled = !1), be.debug("Navigation input locked")
  }
  unlockNavigation() {
    ;(this.navigationEnabled = !0), be.debug("Navigation input unlocked")
  }
  async navigateToSweep(e, t, i?, n?, s?) {
    const r = this.settingsData.tryGetProperty(playerConst.TransitionType, transitionTypeEnum.Interpolate)
    let o
    void 0 === i && (i = r)
    const a = this.sweepData.currentSweep
    if (i === transitionTypeEnum.Interpolate) {
      const t = !a || this.sweepData.isSweepAligned(a),
        n = this.sweepData.isSweepAligned(e),
        s = a !== e,
        r = !t || !n,
        o = this.viewmodeData.isInside()
      s && r && o && (i = transitionTypeEnum.FadeToBlack)
    }
    if (this.viewmodeData.isInside()) {
      const r = void 0 === t && void 0 === n && void 0 === s,
        a = this.cameraData.canTransition() && this.sweepData.canTransition()
      if (i === transitionTypeEnum.Interpolate && this.sweepData.currentSweep !== e && r && (a || this.navigationWalk.isActive)) {
        const t = this.sweepData.getSweep(e)
        o = this.navigationWalk.appendNode(t, this.sweepData.currentSweep)
      } else {
        if (!a) return this.sweepData.currentSweep
        o = this.sweepModule.moveToSweep({
          transitionType: i,
          sweepId: e,
          rotation: t,
          transitionTime: n,
          transitionSpeedMultiplier: s
        })
      }
    } else
      o = this.viewmodeModule.switchToMode(viewmodeEnum.Panorama, i, {
        sweepID: e,
        rotation: t
      })
    return await o, this.sweepData.currentSweep
  }
}
